package com.sec.etech.file.service;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.sec.etech.file.model.EtechFile;
import com.twelvemonkeys.io.FileUtil;
import org.apache.commons.lang3.StringUtils;
import org.openbpm.base.api.exception.BusinessMessage;
import org.openbpm.base.core.util.StringUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class EtechFileHandlerService {
    @Value("${etech.file.base-dir:/app/data2/files/}")
    private String etechFileBaseDir;
    @Value("${etech.file.temp-dir:/app/data2/files/temp/}")
    private String etechFileTemp;
    @Value("${etech.file.upload-dir:/app/data2/files/uploads/}")
    private String fileUploadDir;
    // 模板文件目录
    @Value("${etech.file.template-dir:/app/data2/files/templates/}")
    private String fileTemplateDir;

    /**
     * 根据新旧路径获取文件存储主目录
     *
     * @return
     */
    public String getEtechFileBaseDir(String filePath) {
        String baseDir = null;
        String filePathTmp = URLUtil.decode(filePath);
        filePathTmp = filePathTmp.replaceAll("\\\\", "/");
        if (filePathTmp.split("/").length == 4) {//4段是无模块路径
            baseDir = this.getFileUploadDir();
        }else {
            baseDir = this.getEtechFileBaseDir();
        }
        return baseDir;
    }
    /**
     * 获取文件存储主目录
     *
     * @return
     */
    public String getEtechFileBaseDir() {
        String fileBaseDir = etechFileBaseDir;
        if (!fileBaseDir.endsWith(File.separator)) {
            fileBaseDir = fileBaseDir + File.separator;
        }
        return fileBaseDir;
    }
    /**
     * 获取旧上传器文件存储主目录
     *
     * @return
     */
    public String getFileUploadDir() {
        String fileUploadDir = this.fileUploadDir;
        if (!fileUploadDir.endsWith(File.separator)) {
            fileUploadDir = fileUploadDir + File.separator;
        }
        return fileUploadDir;
    }
    /**
     * 获取临时文件存储目录
     *
     * @return
     */
    public String getEtechFileTempDir() {
        String fileTempDir = etechFileTemp;
        if (!fileTempDir.endsWith(File.separator)) {
            fileTempDir = fileTempDir + File.separator;
        }
        return fileTempDir;
    }
    /**
     * 获取相对路径
     *
     * @param fileName 只包含文件名称和后缀
     * @param module
     * @return
     */
    public String getFileRelativePath(String fileName, String module) {
        //默认etech
        module = StrUtil.isNotBlank(module) ? module : "etech";
        String date = DateUtil.format(new Date(), "yyyy/MM/dd");
        return StrUtil.format("{}/{}/{}", module, date, fileName);
    }
    /**
     * 获取相对路径
     *
     * @param module
     * @return
     */
    public String getFileRelativePath(String module) {
        //默认etech
        module = StrUtil.isNotBlank(module) ? module : "etech";
        String date = DateUtil.format(new Date(), "yyyy/MM/dd");
        return StrUtil.format("{}/{}/", module, date);
    }
    /**
     * 获取文件绝对路径
     *
     * @param fileName 只包含文件名称和后缀
     * @param module
     * @return
     */
    private String getFileAbsolutePath(String fileName, String module) {
        return getEtechFileBaseDir() + getFileRelativePath(fileName, module);
    }

    /**
     * 获取临时文件相对路径
     *
     * @param fileName 只包含文件名称和后缀
     * @return
     */
    public String getTempFileRelativePath(String fileName) {
        return getFileRelativePath(fileName, "temp");
    }

    /**
     * 获取临时文件相对路径不含文件名
     * @return
     */
    public String getTempRelativePath() {
        Date today = new Date();
        return  "temp" + File.separator + DateUtil.format(today, "yyyy") + File.separator
                +  DateUtil.format(today, "MM") + File.separator
                +  DateUtil.format(today, "dd") + File.separator;
    }
    /**
     * 获取临时文件绝对路径
     *
     * @param fileName 只包含文件名称和后缀
     * @return
     */
    public String getTempFileAbsolutePath(String fileName) {
        return getEtechFileBaseDir() + getTempFileRelativePath(fileName);
    }

    /**
     * 获取模板文件绝对路径
     *
     * @param filePath 相对路径
     * @return
     */
    public String getTemplatesFileAbsolutePath(String filePath) {
        return getEtechFileBaseDir() + filePath;
    }

    /**
     * path为文件的相对主目录的路径
     *
     * @param path
     * @return
     */
    public String getAbsolutePath(String path) {
        String absolutePath = path;
        // fix nullpoint
        if(StringUtils.isEmpty(absolutePath)){
            absolutePath = "";
        }
        if (!absolutePath.startsWith("/")) {
            absolutePath = getEtechFileBaseDir() + path;
        }
        return absolutePath;
    }

    /**
     * 下载生成的预览文件
     *
     * @param etechFile
     * @return
     */
    public String getDownloadPreviewPath(EtechFile etechFile) {
        String absolutePath = "";
        String homeDir = getEtechFileBaseDir();
        if (StrUtil.isNotBlank(etechFile.getPreviewPath())) {
            absolutePath = etechFile.getPreviewPath();
        } else if (StrUtil.isNotBlank(etechFile.getThumbnailPath())) {
            //缩略图都是图片竖向合成一张图片
            String newImgFilePath = etechFile.getThumbnailPath().replace(etechFile.getModule(), "temp") + ".jpg";
            try {
                File[] files = FileUtil.list(homeDir + etechFile.getThumbnailPath());
                if (files != null && files.length > 0) {
                    if (files.length > 1) {
                        //大于一张合成成一张
                        mergeVertical(CollUtil.toList(files), newImgFilePath);
                    } else {
                        return etechFile.getThumbnailPath() + "/" + files[0].getName();
                    }
                    return newImgFilePath;
                } else {
                    throw new BusinessMessage("没有生成预览文件，请使用原文件下载！");
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        } else {
            if(etechFile.getPath().endsWith(".pdf") || etechFile.getPath().endsWith(".tif") || etechFile.getPath().endsWith(".TIF")
                    || etechFile.getPath().endsWith(".tiff")){
                absolutePath = etechFile.getPath();
            }else {
                //没有生成预览文件，可能不支持的预览文件
                throw new BusinessMessage("没有生成预览文件，请使用原文件下载！");
            }
        }
        return absolutePath;
    }

    //竖向合成图片
    public static void mergeVertical(List<File> files, String path) {
        try {
            Integer allWidth = 0;    //计算画布总宽
            Integer allHeight = 0;    //计算画布总高
            List<BufferedImage> imgs = new ArrayList<>();
            for (int i = 0; i < files.size(); i++) {
                imgs.add(ImageIO.read(files.get(i)));
                //因为是竖向合成，拿图片里最大的一个宽度就行
                allWidth = Math.max(allWidth, imgs.get(i).getWidth());
                allHeight += imgs.get(i).getHeight();
            }
            BufferedImage combined = new BufferedImage(allWidth, allHeight, BufferedImage.TYPE_INT_RGB);
            Graphics g = combined.getGraphics();
            //设置画布背景颜色 ，默认黑色
            g.setColor(Color.white);
            g.fillRect(0, 0, allWidth, allHeight);
            Integer height = 0;
            for (int i = 0; i < imgs.size(); i++) {
                g.drawImage(imgs.get(i), 0, height, null);
                //+10为了设置上下两个图片间距
                height += imgs.get(i).getHeight() + 10;
            }
            ImageIO.write(combined, "jpg", new File(path));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //横向合成图片
    public static void mergeHorizontal(List<File> files, String path) {
        try {
            Integer allWidth = 0;
            Integer allHeight = 0;
            List<BufferedImage> imgs = new ArrayList<>();
            for (int i = 0; i < files.size(); i++) {
                imgs.add(ImageIO.read(files.get(i)));
                allHeight = Math.max(allHeight, imgs.get(i).getHeight());
                allWidth += imgs.get(i).getWidth();
            }
            BufferedImage combined = new BufferedImage(allWidth, allHeight, BufferedImage.TYPE_INT_RGB);
            Graphics g = combined.getGraphics();
            g.setColor(Color.white);
            g.fillRect(0, 0, allWidth, allHeight);
            Integer width = 0;
            for (int i = 0; i < imgs.size(); i++) {
                g.drawImage(imgs.get(i), width, 0, null);
                //设置横向间距
                width += imgs.get(i).getWidth() + 10;
            }
            ImageIO.write(combined, "jpg", new File(path));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 获取模板文件完整路径
     * @param path
     * @return
     */
    public String getTempleteFilePath(String path) {
        String homePath = getTempleteDir();
        return homePath + path;
    }
    /**
     * 获取模板文件根目录
     *
     * @return
     */
    public String getTempleteDir() {
        String path = fileTemplateDir;
        if (StringUtil.isEmpty(path)) {
            path = getEtechFileBaseDir() + "templates" + File.separator;
        }
        if (cn.hutool.core.io.FileUtil.isDirectory(path)) {
            // 已配置模板文件夹 templates
        } else {
            cn.hutool.core.io.FileUtil.mkdir(path);
        }
        return path;
    }
    public String getFileEncodeType(String path) {
        String charset = "GBK";
        byte[] first3Bytes = new byte[3];
        try {
            boolean checked = false;
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
            bis.mark(100); // 读者注： bis.mark(0);修改为 bis.mark(100);我用过这段代码，需要修改上面标出的地方。
            // Wagsn注：不过暂时使用正常，遂不改之
            int read = bis.read(first3Bytes, 0, 3);
            if (read == -1) {
                bis.close();
                return charset; // 文件编码为 ANSI
            } else if (first3Bytes[0] == (byte) 0xFF && first3Bytes[1] == (byte) 0xFE && first3Bytes[2] == 0x41) {
                charset = "UTF-16LE"; // 文件编码为 Unicode
                checked = true;
            } else if (first3Bytes[0] == (byte) 0xFE && first3Bytes[1] == (byte) 0xFF && first3Bytes[2] == 0x00) {
                charset = "UTF-16BE"; // 文件编码为 Unicode big endian
                checked = true;
            } else if (first3Bytes[0] == (byte) 0xEF && first3Bytes[1] == (byte) 0xBB && first3Bytes[2] == (byte) 0xBF) {
                charset = "UTF-8"; // 文件编码为 UTF-8
                checked = true;
            }
            bis.reset();
            if (!checked) {
                while ((read = bis.read()) != -1) {
                    if (read >= 0xF0)
                        break;
                    if (0x80 <= read && read <= 0xBF) // 单独出现BF以下的，也算是GBK
                        break;
                    if (0xC0 <= read && read <= 0xDF) {
                        read = bis.read();
                        if (0x80 <= read && read <= 0xBF) // 双字节 (0xC0 - 0xDF)
                            // (0x80 - 0xBF),也可能在GB编码内
                            continue;
                        else
                            break;
                    } else if (0xE0 <= read && read <= 0xEF) { // 也有可能出错，但是几率较小
                        read = bis.read();
                        if (0x80 <= read && read <= 0xBF) {
                            read = bis.read();
                            if (0x80 <= read && read <= 0xBF) {
                                charset = "UTF-8";
                                break;
                            } else
                                break;
                        } else
                            break;
                    }
                }
            }
            bis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("--文件-> [" + path + "] 采用的字符集为: [" + charset + "]");
        //log.debug("--文件-> [" + path + "] 采用的字符集为: [" + charset + "]");
        return charset;
    }
}
